home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / PNL Libraries / MyTransport.p < prev    next >
Encoding:
Text File  |  1995-11-02  |  46.6 KB  |  1,818 lines  |  [TEXT/CWIE]

  1. unit MyTransport;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types, OpenTransport, TCPUtils;
  7.     
  8.     var
  9.         have_OT:Boolean;
  10.  
  11.     const
  12.         couldNotGetRequestedPortErr = -99;
  13.             
  14.     const
  15.         kMyStreamClosingErr = connectionClosingErr;
  16.     
  17.     type
  18.         TransportDeferredTaskCookie = longint;
  19.         TransportDeferredTaskProcPtr = ProcPtr; { procedure(arg:ptr) }
  20.         TransportRef = ^integer;
  21.         TransportUDPRef = ^point;
  22.     
  23.     type
  24.         IPAddrArray = array[1..1000] of IPAddr;
  25.         IPAddrArrayPtr = ^IPAddrArray;
  26.  
  27.     type
  28.         MemoryReleasedProc = procedure (tref: TransportRef; result: OTResult; cookie: univ Ptr);
  29.  
  30.     var
  31.         hack_MemoryReleasedProc: MemoryReleasedProc;
  32. { * means Interupt-safe }
  33.  
  34.     procedure StartupTransport;
  35.     procedure ConfigureTransport(allow_OT: Boolean);
  36.     
  37.     function OpenTransportSystem:OSStatus;
  38.     procedure CloseTransportSystem;
  39.  
  40.     function TransportUDPOpenPort(var tref: TransportUDPRef; var localport: integer; buffer_size:longint): OSStatus;
  41.     procedure TransportUDPDestroy (var tref: TransportUDPRef);
  42.     function TransportUDPDatagramsAvailable (tref: TransportUDPRef): longint;
  43.     function TransportUDPRead (tref: TransportUDPRef; var remoteIP: longint; var remoteport: integer;
  44.                                     var datap: ptr; var datalen: integer): OSStatus;
  45.     function TransportUDPReturnBuffer (tref: TransportUDPRef; datap: ptr): OSStatus;
  46.     function TransportUDPWrite (tref: TransportUDPRef; remoteIP: longint; remoteport: integer;
  47.                                     datap: ptr; datalen: integer; checksum: boolean): OSStatus;
  48.     
  49.     function TransportListen(var token:Ptr; localport:integer; listeners:integer; buffer_size:longint):OSStatus;
  50.     function TransportGetListenerConnection(token:Ptr; var tref:TransportRef):OSStatus;
  51.     procedure TransportDestroyListener(var token:Ptr);
  52.  
  53.     function TransportOpenActiveConnection(var tref:TransportRef; dest:Str255; localport:integer; buffer_size:longint): OSStatus;
  54.     function TransportOpenPassiveConnection(var tref:TransportRef; var localport:integer; buffer_size:longint): OSStatus;
  55.     procedure TransportGetOpenResult(tref:TransportRef; var result: OSStatus); { * }
  56.     
  57.     procedure TransportDestroy(var tref:TransportRef);
  58.  
  59.     function TransportGetConnectionState (tref:TransportRef): TCPStateType; { * }
  60.     function TransportGetPorts(tref:TransportRef; var localip: IPAddr; var localport: integer; var remoteip: longint; var remoteport: integer): OSStatus;
  61.     procedure TransportSendClose(tref:TransportRef);
  62.  
  63.     function TransportHandleTransfers(tref:TransportRef): OSStatus;
  64.  
  65.     function TransportHandleReceives(tref:TransportRef): OSStatus;
  66.     function TransportReceive(tref:TransportRef; buf: Ptr; len:longint; var count:longint): OSStatus;
  67.     function TransportCharsAvailable(tref:TransportRef): longint;
  68.  
  69.     function TransportHandleSends(tref:TransportRef): OSStatus;
  70.     function TransportSend(tref:TransportRef; buf: Ptr; len:longint): OSStatus;
  71.     
  72.     procedure TransportLowGetStreamPtr(tref:TransportRef; var stream: StreamPtr);
  73.     procedure TransportLowGetEndpointRef(tref:TransportRef; var ep: EndpointRef);
  74.     function TransportLowSetOTAckSends(tref:TransportRef; handler: MemoryReleasedProc): OSStatus;
  75.     
  76.     function TransportGetMyIPAddr(var ip:IPAddr): OSStatus;
  77.     
  78.     function TransportCreateDeferredTask(proc: OTProcessProcPtr; arg: UNIV Ptr): TransportDeferredTaskCookie;
  79.     procedure ScheduleDeferredTask(cookie:TransportDeferredTaskCookie); { * }
  80.     procedure DestroyDeferredTaskCookie(cookie:TransportDeferredTaskCookie);
  81.  
  82.     procedure TransportEnterInterrupt;
  83.     procedure TransportLeaveInterrupt;
  84.     
  85.     function TransportNameToAddr(name: Str255; var token: Ptr): OSStatus;
  86.     procedure TransportGetNameToAddrResult(var token: Ptr; var result: OSStatus; name:StringPtr; addrs:IPAddrArrayPtr; len:integer); { * }
  87.  
  88.     function TransportAddrToName(addr: IPAddr; var token: Ptr): OSStatus;
  89.     procedure TransportGetAddrToNameResult(var token: Ptr; var result: OSStatus; var name:Str255); { * }
  90.  
  91.     procedure TransportAbortDNR(var token: Ptr);
  92.  
  93.     function StringToIPAddr (s: Str255; var addr: longInt): boolean;
  94.     procedure IPAddrToString (ip: longInt; var addrStr: Str255);
  95.     function IPAddrToStr (ip: longInt): Str255;
  96.     procedure IPAddrPortToString (ip: longInt; port: integer; var addrStr: Str255);
  97.     function IPAddrPortToStr (ip: longInt; port: integer): Str255;
  98.  
  99. implementation
  100.  
  101.     uses
  102.         Events, TextUtils, OpenTptInternet, GestaltEqu, Devices, CodeFragments,
  103.         MyCStrings, MyAssertions, DNR, MyStrings, MyMathUtils, 
  104.         MyUtils, MyMemory, MyCallProc, QLowLevel, PreserveA5, MyStartup;
  105.  
  106.     const
  107.         use_OT_tasks = true;
  108.     
  109.     type
  110.         TransportUDPRecord = record
  111.             case boolean of
  112.             false:(
  113.                 stream: StreamPtr;
  114.                 stream_buffer: Ptr;
  115.                 outstanding_packets: longint;
  116.             )
  117.             true:(
  118.                 ep: EndpointRef;
  119.                 received_packets, read_packets: longint;
  120.             )
  121.         end;
  122.         TransportUDPRecordPtr = ^TransportUDPRecord;
  123.         
  124.     type
  125.         TransportRecord = record
  126.             next: TransportRecordPtr;
  127.             input_handle: Handle;
  128.             output_handle: Handle;
  129.             sending_handle: Handle;
  130.             send_error, receive_error: OSStatus;
  131.             open_result: OSStatus;
  132.             started_opening: Boolean;
  133.             handle_receives, handle_sends: Boolean;
  134.             do_send_close: Boolean;
  135.             case boolean of
  136.             false:(
  137.                 remote_port:integer;
  138.                 local_port:integer;
  139.                 stream:StreamPtr;
  140.                 stream_buffer:Ptr;
  141.                 open_cb, close_cb, send_cb:TCPControlBlock;
  142.                 send_wds: wdsType;
  143.                 dnr_token:Ptr;
  144.                 tstate:TCPStateType;
  145.             )
  146.             true:(
  147.                 ep: EndpointRef;
  148.                 rcvCall, sndCall: TCall;
  149.                 rcvsin: InetAddress;
  150.                 sndsin: DNSAddress;
  151.                 waiting_for_connect: Boolean;
  152.                 connect_received: Boolean;
  153.                 accept_received: Boolean;
  154.                 passcon_received: Boolean;
  155.                 disconnect_received: Boolean;
  156.                 getprotaddr_result: OSStatus;
  157.                 connect_result:OSStatus;
  158.                 accept_result:OSStatus;
  159.                 passcon_result:OSStatus;
  160.                 MemoryReleasedHandler: MemoryReleasedProc;
  161.             )
  162.         end;
  163.         TransportRecordPtr = ^TransportRecord;
  164.  
  165.     type
  166.         MyDeferredTask = record
  167.             dt:DeferredTask;
  168.             fired:Boolean;
  169.             completion:UniversalProcPtr;
  170.             real_arg:longint;
  171.         end;
  172.         MyDeferredTaskPtr = ^MyDeferredTask;
  173.     
  174.     type
  175.         XInetHostInfo = record
  176.             host:InetHostInfo;
  177.             result:OSStatus;
  178.         end;
  179.         XInetHostInfoPtr = ^XInetHostInfo;
  180.         TDNRRecord = record
  181.             next:TDNRRecordPtr;
  182.             kind: (TK_NameToAddr, TK_AddrToName);
  183.             dead: Boolean;
  184.             case boolean of
  185.                 true:(
  186.                     dr:DNRRecord;
  187.                     canonical_name: Str255;
  188.                 );
  189.                 false:(
  190.                     xhost:XInetHostInfo; { Warning InetHostInfo must *start* with an InetDomainName! }
  191.                 );
  192.         end;
  193.         TDNRRecordPtr = ^TDNRRecord;
  194.         
  195.     var
  196.         transports:QHdr;
  197.         gMyDeferredTaskHandlerProc : UniversalProcPtr;
  198.         tcp_is_open:Boolean;
  199.         is_ref:InetSvcRef;
  200.         is_result: OTResult;
  201.         dnrs:QHdr;
  202.         
  203.     procedure InternetServicesHandler(context:Ptr; event: OTEventCode; result: OTResult; cookie: XInetHostInfoPtr);
  204.     begin
  205.         context := context; { UNUSED! }
  206.         case event of
  207.             T_OPENCOMPLETE: begin
  208.                 is_ref := InetSvcRef(cookie);
  209.                 is_result := result;
  210.             end;
  211.             T_DNRSTRINGTOADDRCOMPLETE, T_DNRADDRTONAMECOMPLETE: begin
  212.                 cookie^.result := result;
  213.             end;
  214.             otherwise
  215.                 ;
  216.         end;
  217.     end;
  218.  
  219.     function WaitForInternetServices: OSStatus;
  220.     begin
  221.         while is_result = inProgress do begin
  222.         end;
  223.         WaitForInternetServices := is_result;
  224.     end;
  225.     
  226.     function TransportNameToAddr(name: Str255; var token: Ptr): OSStatus;
  227.         var
  228.             err: OSStatus;
  229.             tdrp:TDNRRecordPtr;
  230.     begin
  231.         tdrp := nil;
  232.         err := OpenTransportSystem;
  233.         if err = noErr then begin
  234.             err := MNewPtr(tdrp, SizeOf(TDNRRecord));
  235.         end;
  236.         if err = noErr then begin
  237.             tdrp^.kind := TK_NameToAddr;
  238.             tdrp^.dead := false;
  239.             if have_OT then begin
  240.                 tdrp^.xhost.result := inProgress;
  241.                 P2C(@name);
  242.                 err := WaitForInternetServices;
  243.                 if err = noErr then begin
  244.                     err := OTInetStringToAddress(is_ref, @name, tdrp^.xhost.host);
  245.                 end;
  246.             end else begin
  247.                 tdrp^.canonical_name := name;
  248.                 DNRNameToAddr(name, @tdrp^.dr, nil);
  249.                 err := noErr;
  250.             end;
  251.         end;
  252.         if err = noErr then begin
  253.             Enqueue(QElemPtr(tdrp),@dnrs);
  254.         end else begin
  255.             MDisposePtr(tdrp);
  256.         end;
  257.         token := Ptr(tdrp);
  258.         TransportNameToAddr := err;
  259.     end;
  260.     
  261.     procedure TransportGetNameToAddrResult(var token: Ptr; var result: OSStatus; name:StringPtr; addrs:IPAddrArrayPtr; len:integer);
  262.         var
  263.             tdrp:TDNRRecordPtr;
  264.             i:integer;
  265.             junk: OSStatus;
  266.     begin
  267.         tdrp := TDNRRecordPtr(token);
  268.         result := -1;
  269.         if tdrp <> nil then begin
  270.             if have_OT then begin
  271.                 result := tdrp^.xhost.result;
  272.                 if result = noErr then begin
  273.                     if name <> nil then begin
  274.                         CopyC2P(@tdrp^.xhost.host.name, name^);
  275.                     end;
  276.                     for i := 1 to len do begin
  277.                         addrs^[i] := 0;
  278.                     end;
  279.                     for i := 1 to Min(kMaxHostAddrs, len) do begin
  280.                         addrs^[i] := tdrp^.xhost.host.addrs[i-1];
  281.                     end;
  282.                 end;
  283.             end else begin
  284.                 result := tdrp^.dr.ioResult;
  285.                 if result = noErr then begin
  286.                     if name <> nil then begin
  287.                         name^ := tdrp^.canonical_name;
  288.                     end;
  289.                     for i := 1 to len do begin
  290.                         addrs^[i] := 0;
  291.                     end;
  292.                     for i := 1 to Min(len, 4) do begin
  293.                         addrs^[i] := tdrp^.dr.hi.addrs[i];
  294.                     end;
  295.                 end;
  296.             end;
  297.             if result <> inProgress then begin
  298.                 junk := Dequeue(QElemPtr(tdrp),@dnrs);
  299.                 MDisposePtr(tdrp);
  300.                 token := nil;
  301.             end;
  302.         end;
  303.     end;
  304.     
  305.     function TransportAddrToName(addr: IPAddr; var token: Ptr): OSStatus;
  306.         var
  307.             err: OSStatus;
  308.             tdrp:TDNRRecordPtr;
  309.     begin
  310.         tdrp := nil;
  311.         err := OpenTransportSystem;
  312.         if err = noErr then begin
  313.             err := MNewPtr(tdrp, SizeOf(TDNRRecord));
  314.         end;
  315.         if err = noErr then begin
  316.             tdrp^.kind := TK_AddrToName;
  317.             tdrp^.dead := false;
  318.             if have_OT then begin
  319.                 tdrp^.xhost.result := inProgress;
  320.                 err := WaitForInternetServices;
  321.                 if err = noErr then begin
  322.                     err := OTInetAddressToName(is_ref, addr, tdrp^.xhost.host.name);
  323.                 end;
  324.             end else begin
  325.                 DNRAddrToName(addr, @tdrp^.dr, nil);
  326.                 err := noErr;
  327.             end;
  328.         end;
  329.         if err = noErr then begin
  330.             Enqueue(QElemPtr(tdrp),@dnrs);
  331.         end else begin
  332.             MDisposePtr(tdrp);
  333.         end;
  334.         token := Ptr(tdrp);
  335.         TransportAddrToName := err;
  336.     end;
  337.     
  338.     procedure TransportGetAddrToNameResult(var token: Ptr; var result: OSStatus; var name:Str255);
  339.         var
  340.             tdrp:TDNRRecordPtr;
  341.             junk: OSStatus;
  342.     begin
  343.         tdrp := TDNRRecordPtr(token);
  344.         result := -1;
  345.         if tdrp <> nil then begin
  346.             if have_OT then begin
  347.                 result := tdrp^.xhost.result;
  348.                 if result = noErr then begin
  349.                     CopyC2P(@tdrp^.xhost.host.name, name);
  350.                 end;
  351.             end else begin
  352.                 result := tdrp^.dr.ioResult;
  353.                 if result = noErr then begin
  354.                     name := tdrp^.dr.name;
  355.                 end;
  356.             end;
  357.             if result <> inProgress then begin
  358.                 junk := Dequeue(QElemPtr(tdrp),@dnrs);
  359.                 MDisposePtr(tdrp);
  360.                 token := nil;
  361.             end;
  362.         end;
  363.         if (result = noErr) & (name[length(name)] = '.') then begin
  364.             Delete(name, length(name), 1);
  365.         end;
  366.     end;
  367.     
  368.     procedure TransportAbortDNR(var token: Ptr);
  369.         var
  370.             tdrp:TDNRRecordPtr;
  371.     begin
  372.         if token <> nil then begin
  373.             tdrp := TDNRRecordPtr(token);
  374.             tdrp^.dead := true;
  375.         end;
  376.     end;
  377.  
  378.     procedure IdleDNR(this:TDNRRecordPtr);
  379.         var
  380.             result: OSStatus;
  381.             name:Str255;
  382.     begin
  383.         case this^.kind of
  384.             TK_NameToAddr: begin
  385.                 TransportGetNameToAddrResult(Ptr(this), result, nil, nil, 0);
  386.             end;
  387.             TK_AddrToName: begin
  388.                 TransportGetAddrToNameResult(Ptr(this), result, name);
  389.             end;
  390.         end;
  391.     end;
  392.     
  393.     procedure IdleDNRs;
  394.         var
  395.             this, next:TDNRRecordPtr;
  396.     begin
  397.         this := TDNRRecordPtr(dnrs.qHead);
  398.         while this <> nil do begin
  399.             next := this^.next;
  400.             if this^.dead then begin
  401.                 IdleDNR(this);
  402.             end;
  403.             this := next;
  404.         end;
  405.     end;
  406.     
  407.     function StringToIPAddr (s: Str255; var addr: longInt): boolean;
  408.         var
  409.             good: boolean;
  410.         procedure Get1;
  411.             var
  412.                 b: integer;
  413.         begin
  414.             if (length(s) = 0) | not (s[1] in ['0'..'9']) then begin
  415.                 good := false;
  416.             end else begin
  417.                 b := ord(s[1]) - 48;
  418.                 s := TPCopy(s, 2, 255);
  419.                 if (s <> '') & (s[1] in ['0'..'9']) then begin
  420.                     b := b * 10 + ord(s[1]) - 48;
  421.                     s := TPCopy(s, 2, 255);
  422.                 end;
  423.                 if (s <> '') & (s[1] in ['0'..'9']) then begin
  424.                     b := b * 10 + ord(s[1]) - 48;
  425.                     s := TPCopy(s, 2, 255);
  426.                 end;
  427.                 if (s <> '') & (s[1] = '.') then begin
  428.                     s := TPCopy(s, 2, 255);
  429.                 end;
  430.                 if b > 255 then begin
  431.                     good := false;
  432.                     b := 0; { avoid overflow error? }
  433.                 end;
  434.                 addr := BOR(BSL(addr, 8), b);
  435.             end;
  436.         end;
  437.     begin
  438.         good := true;
  439.         addr := 0;
  440.         Get1;
  441.         Get1;
  442.         Get1;
  443.         Get1;
  444.         good := good & (s = '');
  445.         if not good then begin
  446.             addr := 0;
  447.         end;
  448.         StringToIPAddr := good;
  449.     end;
  450.  
  451.     procedure IPAddrToString (ip: longInt; var addrStr: Str255);
  452.         function GetByte(ip: longint; bits: integer): Str255;
  453.             var
  454.                 t:Str255;
  455.         begin
  456.              NumToString(band(bsr(ip, bits), $00FF), t);
  457.              GetByte := t;
  458.         end;
  459.     begin
  460.         addrStr := GetByte(ip, 24);
  461.         addrStr := concat(addrStr, '.', GetByte(ip, 16));
  462.         addrStr := concat(addrStr, '.', GetByte(ip, 8));
  463.         addrStr := concat(addrStr, '.', GetByte(ip, 0));
  464.     end;
  465.  
  466.     function IPAddrToStr (ip: longInt): Str255;
  467.         var
  468.             s: Str255;
  469.     begin
  470.         IPAddrToString(ip, s);
  471.         IPAddrToStr := s;
  472.     end;
  473.  
  474.     procedure IPAddrPortToString (ip: longInt; port: integer; var addrStr: Str255);
  475.         var
  476.             ns:Str255;
  477.     begin
  478.         NumToString(port, ns);
  479.         addrStr := concat(IPAddrToStr(ip),':', ns);
  480.     end;
  481.     
  482.     function IPAddrPortToStr (ip: longInt; port: integer): Str255;
  483.         var
  484.             ns:Str255;
  485.     begin
  486.         NumToString(port, ns);
  487.         IPAddrPortToStr := concat(IPAddrToStr(ip),':', ns);
  488.     end;
  489.     
  490.     procedure WaitForDNRCompletions;
  491.         var
  492.             this:TDNRRecordPtr;
  493.     begin
  494.         if not have_OT then begin
  495.             while dnrs.qHead <> nil do begin
  496.                 this := TDNRRecordPtr(dnrs.qHead);
  497.                 IdleDNR(this);
  498.             end;
  499.         end;
  500.     end;
  501.     
  502. { Deferred Tasks }
  503.     
  504.     procedure MyDeferredTaskHandlerPascal(dtp: MyDeferredTaskPtr);
  505.         var
  506.             olda5:Ptr;
  507.     begin
  508.         olda5 := SetPreservedA5;
  509.         dtp^.fired := true;
  510.         CallPascal04(dtp^.real_arg, dtp^.completion);
  511.         RestoreA5(olda5);
  512.     end;
  513.  
  514. {$IFC GENERATINGPOWERPC}
  515.     procedure MyDeferredTaskHandler(dtp: MyDeferredTaskPtr);
  516.     begin
  517.         MyDeferredTaskHandlerPascal(dtp);
  518.     end;
  519. {$ELSEC}
  520.     procedure MyDeferredTaskHandler;
  521.         var
  522.             param:MyDeferredTaskPtr;
  523.     begin
  524.         param := MyDeferredTaskPtr(GetRegA1);
  525.         MyDeferredTaskHandlerPascal(param);
  526.     end;
  527. {$ENDC}
  528.  
  529.     function TransportCreateDeferredTask(proc: OTProcessProcPtr; arg: UNIV Ptr): TransportDeferredTaskCookie;
  530.         var
  531.             dtp:MyDeferredTaskPtr;
  532.             result:longint;
  533.     begin
  534.         result := 0;
  535.         if have_OT & use_OT_tasks then begin
  536.             if OpenTransportSystem = noErr then begin
  537.                 result := OTCreateDeferredTask(proc, arg);
  538.             end;
  539.         end else begin
  540.             dtp := MyDeferredTaskPtr(NewPtr(SizeOf(MyDeferredTask)));
  541.             if dtp <> nil then begin
  542.                 dtp^.dt.dtAddr := gMyDeferredTaskHandlerProc;
  543.                 dtp^.dt.dtParam := longint(dtp);
  544.                 dtp^.dt.dtReserved := 0;
  545.                 dtp^.dt.dtFlags := 0;
  546.                 dtp^.dt.qType := ord(dtQType);
  547.                 dtp^.completion := NewProc(proc, uppPascal04ProcInfo);
  548.                 dtp^.real_arg := longint(arg);
  549.                 dtp^.fired := true;
  550.                 result := TransportDeferredTaskCookie(dtp);
  551.             end;
  552.         end;
  553.         TransportCreateDeferredTask := result;
  554.     end;
  555.  
  556.     procedure ScheduleDeferredTask(cookie:TransportDeferredTaskCookie);
  557.         var
  558.             dummy:Boolean;
  559.             dtp:MyDeferredTaskPtr;
  560.     begin
  561.         if have_OT & use_OT_tasks then begin
  562.             dummy := OTScheduleDeferredTask(cookie);
  563.         end else begin
  564.             dtp := MyDeferredTaskPtr(cookie);
  565.             if dtp^.fired then begin
  566.                 if DTInstall(DeferredTaskPtr(dtp)) = noErr then begin
  567.                     dtp^.fired := false;
  568.                 end;
  569.             end;
  570.         end;
  571.     end;
  572.  
  573.     procedure DestroyDeferredTaskCookie(cookie:TransportDeferredTaskCookie);
  574.         var
  575.             junk:OSStatus;
  576.             dtp:MyDeferredTaskPtr;
  577.     begin
  578.         if have_OT & use_OT_tasks then begin
  579.             junk := OTDestroyDeferredTask(cookie);
  580.         end else begin
  581.             dtp := MyDeferredTaskPtr(cookie);
  582.             while not dtp^.fired do begin
  583.                 { wait til it fires since we can't abort it }
  584.             end;
  585.             DisposeRoutineDescriptor(dtp^.completion);
  586.             DisposePtr(Ptr(cookie));
  587.         end;
  588.     end;
  589.  
  590.     procedure TransportEnterInterrupt;
  591.     begin
  592.         if have_OT then begin
  593.             OTEnterInterrupt;
  594.         end;
  595.     end;
  596.     
  597.     procedure TransportLeaveInterrupt;
  598.     begin
  599.         if have_OT then begin
  600.             OTLeaveInterrupt;
  601.         end;
  602.     end;
  603.  
  604.     function OpenTransportSystemOT:OSStatus;
  605.         var
  606.             err: OSStatus;
  607.     begin
  608.         err :=     InitOpenTransport;
  609.         if err = noErr then begin
  610.             is_result := inProgress;
  611.             is_ref := nil;
  612.             err := OTAsyncOpenInternetServices(OTConfigurationPtr(kDefaultInternetServicesPath), 0, @InternetServicesHandler,nil);
  613.             if err <> noErr then begin
  614.                 is_result := err;
  615.             end;
  616.         end;
  617.         OpenTransportSystemOT := err;
  618.     end;
  619.     
  620.     procedure CloseTransportSystemOT;
  621.         var
  622.             junk:OSStatus;
  623.     begin
  624.         if is_ref <> nil then begin
  625.             junk := OTCloseProvider(is_ref);
  626.         end;
  627.         CloseOpenTransport;
  628.     end;
  629.     
  630.     function TransportGetConnectionStateOT(ep: EndpointRef):TCPStateType;
  631.         var
  632.             result: OTResult;
  633.             state:TCPStateType;
  634.     begin
  635.         result := OTGetEndpointState(ep);
  636.         state := T_Dead;
  637.         if result >= 0 then begin
  638.             case result of
  639.                 T_UNINIT, T_UNBND:
  640.                     state := T_Dead;
  641.                 T_IDLE:begin
  642.                     state := T_Bored;
  643.                 end;
  644.                 T_INCON, T_OUTCON:
  645.                     state := T_Opening;
  646.                 T_DATAXFER:
  647.                     state := T_Established;
  648.                 T_OUTREL:
  649.                     state := T_Closing;
  650.                 T_INREL:
  651.                     state := T_PleaseClose;
  652.                 otherwise begin
  653.                     state := T_Unknown;
  654.                 end;
  655.             end;
  656.         end;
  657.         TransportGetConnectionStateOT := state;
  658.     end;
  659.  
  660. { MacTCP routines }
  661.  
  662.     function OpenTransportSystemMT:OSStatus;
  663.         var
  664.             err:OSStatus;
  665.     begin
  666.         err := OpenDriver('.IPP', mactcp_driver_refnum);
  667.         if err = noErr then begin
  668.             err := OpenResolver;
  669.         end;
  670.         OpenTransportSystemMT :=     err;
  671.     end;
  672.     
  673.     procedure CloseTransportSystemMT;
  674.     begin
  675.         CloseResolver;
  676.     end;
  677.  
  678. { Generic routines }
  679.  
  680.     function OpenTransportSystem:OSStatus;
  681.         var
  682.             err:OSStatus;
  683.     begin
  684.         if tcp_is_open then begin
  685.             err := noErr;
  686.         end else if have_OT then begin
  687.             err := OpenTransportSystemOT;
  688.         end else begin
  689.             err := OpenTransportSystemMT;
  690.         end;
  691.         tcp_is_open := err = noErr;
  692.         OpenTransportSystem := err;
  693.     end;
  694.     
  695.     procedure CloseTransportSystem;
  696.     begin
  697.         if tcp_is_open then begin
  698.             if have_OT then begin
  699.                 CloseTransportSystemOT;
  700.             end else begin
  701.                 CloseTransportSystemMT;
  702.             end;
  703.         end;
  704.     end;
  705.  
  706.     function TransportGetMyIPAddr(var ip:IPAddr): OSStatus;
  707.         var
  708.             err: OSStatus;
  709.             cb: IPControlBlock;
  710.             info:InetInterfaceInfo;
  711.     begin
  712.         err := OpenTransportSystem;
  713.         if err = noErr then begin
  714.             if have_OT then begin
  715.                 err := OTInetGetInterfaceInfo(info, 0);
  716.                 ip := info.fAddress
  717.             end else begin
  718.                 MZero(@cb, SizeOf(cb));
  719.                 cb.ioCRefNum := mactcp_driver_refnum;
  720.                 cb.csCode := TCPcsGetMyIP;
  721.                 err := PBControlSync(@cb);
  722.                 ip := cb.getmyip.ourAddress;
  723.             end;
  724.         end;
  725.         TransportGetMyIPAddr := err;
  726.     end;
  727.     
  728. { Open }
  729.  
  730.     function CreateOTEndpoint(var ep:EndpointRef; proc:OTNotifyProcPtr; context:univ Ptr):OSErr;
  731.         var
  732.             err, junk: OSStatus;
  733.             config: Str255;
  734.             info: TEndpointInfo;
  735.     begin
  736.         config := 'tcp';
  737.         P2C(@config);
  738.         ep:=OTOpenEndpoint(OTCreateConfiguration(@config),0,info,err);
  739.         if err = noErr then begin
  740.             if proc <> nil then begin
  741.                 err:=OTInstallNotifier(ep, proc, context);
  742.             end;
  743.             if err <> noErr then begin
  744.                 junk := OTCloseProvider(ep);
  745.             end;
  746.         end;
  747.         CreateOTEndpoint := err;
  748.     end;
  749.     
  750.     procedure OTInitNetbuf(var nb:TNetbuf; buf:Ptr; len:size);
  751.     begin
  752.         nb.buf := buf;
  753.         nb.len := len;
  754.         nb.maxlen := len;
  755.     end;
  756.     
  757.     function SetReuseAddr(ep:EndpointRef):OSErr;
  758.         var
  759.             optreq:TOptMgmt;
  760.             optBuffer:record
  761.                 header:TOptionHeader;
  762.                 value:longint;
  763.             end;
  764.     begin
  765.         optreq.flags := T_NEGOTIATE;
  766.         OTInitNetbuf(optreq.opt, @optBuffer, kOTFourByteOptionSize);
  767.         optBuffer.header.len := kOTFourByteOptionSize;
  768.         optBuffer.header.level := INET_IP;
  769.         optBuffer.header.optionName := IP_REUSEADDR;
  770.         optBuffer.header.status := 0;
  771.         optBuffer.value := $01000000;
  772.         SetReuseAddr := OTOptionManagement(ep, optreq, optreq);
  773.     end;
  774.  
  775.     function BindOTListener(ep:EndpointRef; var localport:integer; listeners:integer):OSErr;
  776.         var
  777.             err:OSStatus;
  778.             reqsin, retsin:InetAddress;
  779.             req, ret:TBind;
  780.     begin
  781.         MZero(@req, sizeof(req));
  782.         err := noErr;
  783.         if localport <> 0 then begin
  784.             err := SetReuseAddr(ep);
  785.             OTInitInetAddress(reqsin, localport, 0);
  786.             OTInitNetbuf(req.addr, @reqsin, sizeof(InetAddress));
  787.         end else begin
  788.             OTInitNetbuf(req.addr, nil, 0);
  789.         end;
  790.         req.qlen := listeners;
  791.         
  792.         MZero(@ret, sizeof(ret));
  793.         OTInitNetbuf(ret.addr, @retsin, sizeof(InetAddress));
  794.         
  795.         if err = noErr then begin
  796.             err := OTBind(ep, @req, @ret);
  797.             if (localport <> 0) & (localport <> retsin.fPort) then begin
  798.                 err := couldNotGetRequestedPortErr;
  799.             end;
  800.             localport := retsin.fPort;
  801.         end;
  802.         
  803.         if err = noErr then begin
  804.             err:=OTSetAsynchronous(ep);
  805.         end;
  806.         BindOTListener := err;
  807.     end;
  808.     
  809.     procedure EventHandlerOT (btp:TransportRecordPtr; event: OTEventCode; result: OTResult; cookie: univ Ptr);
  810.         var
  811.             junk:OSStatus;
  812.     begin
  813.         cookie := cookie; { UNUSED! }
  814.         case event of
  815.             T_OPENCOMPLETE: begin
  816.             end;
  817.             T_ACCEPTCOMPLETE:  begin
  818.                 btp^.accept_result := result;
  819.                 btp^.accept_received := true;
  820.             end;
  821.             T_PASSCON: begin
  822.                 btp^.passcon_result := result;
  823.                 btp^.passcon_received := true;
  824.             end;
  825.             T_CONNECT:  begin
  826.                 btp^.connect_result := result;
  827.                 btp^.connect_received := true;
  828.                 junk := OTRcvConnect(btp^.ep, btp^.rcvCall);
  829.             end;
  830.             T_DISCONNECT:  begin
  831.                 btp^.connect_result := result;
  832.                 btp^.disconnect_received := true;
  833.                 junk := OTRcvDisconnect(btp^.ep, nil);
  834.             end;
  835.             T_GETPROTADDRCOMPLETE: begin
  836.                 btp^.getprotaddr_result := result
  837.             end;
  838.             T_ORDREL:  begin
  839.                 junk := OTRcvOrderlyDisconnect(btp^.ep);
  840.             end;
  841.             T_DATA, T_GODATA, T_DISCONNECTCOMPLETE: begin
  842.             end;
  843.             T_MEMORYRELEASED: begin
  844.                 if btp^.MemoryReleasedHandler <> nil then begin
  845.                     btp^.MemoryReleasedHandler(TransportRef(btp), result, cookie);
  846.                 end;
  847.             end;
  848.             otherwise
  849.                 ;
  850.         end;
  851.     end;
  852.  
  853.     procedure TransportDestroy(var tref:TransportRef);
  854.         var
  855.             btp:TransportRecordPtr;
  856.             junk:OSStatus;
  857.     begin
  858.         btp := TransportRecordPtr(tref);
  859.         if btp <> nil then begin
  860.             if have_OT then begin
  861.                 if btp^.ep <> nil then begin
  862.                     junk := OTCloseProvider(btp^.ep);
  863.                 end;
  864.             end else begin
  865.                 if btp^.stream <> nil then begin
  866.                     junk := MTTCPRelease(btp^.stream);
  867.                 end;
  868.                 MDisposePtr(btp^.stream_buffer);
  869.                 TransportAbortDNR(btp^.dnr_token);
  870.             end;
  871.             MDisposeHandle(btp^.input_handle);
  872.             MDisposeHandle(btp^.output_handle);
  873.             MDisposeHandle(btp^.sending_handle);
  874.             junk:=Dequeue(QElemPtr(btp),@transports);
  875.             MDisposePtr(btp);
  876.         end;
  877.     end;
  878.     
  879.     function TransportCreate(var btp:TransportRecordPtr; buffer_size:longint):OSStatus;
  880.         var
  881.             err:OSStatus;
  882.             hack_mrp: MemoryReleasedProc;
  883.     begin
  884.         hack_mrp := hack_MemoryReleasedProc;
  885.         hack_MemoryReleasedProc := nil;
  886.         buffer_size := Pin(10240, buffer_size, 64512);
  887.         btp := nil;
  888.         err := OpenTransportSystem;
  889.         if err = noErr then begin
  890.             err := MNewPtr(btp, SizeOf(TransportRecord));
  891.             if err = noErr then begin
  892.                 Enqueue(QElemPtr(btp),@transports);
  893.                 btp^.input_handle := nil;
  894.                 btp^.output_handle := nil;
  895.                 btp^.sending_handle := nil;
  896.                 if have_OT then begin
  897.                     btp^.MemoryReleasedHandler := hack_mrp;
  898.                     btp^.waiting_for_connect := false;
  899.                     btp^.connect_received := false;
  900.                     btp^.accept_received := false;
  901.                     btp^.passcon_received := false;
  902.                     btp^.disconnect_received := false;
  903.                     err := CreateOTEndpoint(btp^.ep, @EventHandlerOT, btp);
  904.                     if (err = noErr) & (btp^.MemoryReleasedHandler <> nil) then begin
  905.                         err := OTAckSends(btp^.ep);
  906.                     end;
  907.                 end else begin
  908.                     btp^.dnr_token := nil;
  909.                     btp^.stream := nil;
  910.                     btp^.send_cb.ioResult := noErr;
  911.                     err := MNewPtr(btp^.stream_buffer, buffer_size);
  912.                     if err = noErr then begin
  913.                         err := MTTCPCreate(btp^.stream, btp^.stream_buffer, buffer_size);
  914.                     end;
  915.                 end;
  916.                 btp^.started_opening := false;
  917.                 btp^.handle_receives := false;
  918.                 btp^.handle_sends := false;
  919.                 btp^.do_send_close := false;
  920.                 btp^.send_error := noErr;
  921.                 btp^.open_result := inProgress;
  922.                 btp^.tstate := T_Bored;
  923.                 btp^.receive_error := noErr;
  924.                 if err <> noErr then begin
  925.                     TransportDestroy(TransportRef(btp));
  926.                 end;
  927.             end;
  928.         end;
  929.         TransportCreate := err;
  930.     end;
  931.     
  932.     function TransportHandleReceives(tref:TransportRef): OSStatus;
  933.         var
  934.             err, err2: OSStatus;
  935.             btp:TransportRecordPtr;
  936.     begin
  937.         btp := TransportRecordPtr(tref);
  938.         Assert(btp <> nil);
  939.         err := noErr;
  940.         if not btp^.handle_receives then begin
  941.             btp^.handle_receives := true;
  942.             err2 := MNewHandle(btp^.input_handle, 0);
  943.             if err = noErr then begin
  944.                 err := err2;
  945.             end;
  946.         end;
  947.         TransportHandleReceives := err;
  948.     end;
  949.     
  950.     function TransportHandleSends(tref:TransportRef): OSStatus;
  951.         var
  952.             err, err2: OSStatus;
  953.             btp:TransportRecordPtr;
  954.     begin
  955.         btp := TransportRecordPtr(tref);
  956.         Assert(btp <> nil);
  957.         err := noErr;
  958.         if not btp^.handle_sends then begin
  959.             btp^.handle_sends := true;
  960.             err2 := MNewHandle(btp^.output_handle, 0);
  961.             if err = noErr then begin
  962.                 err := err2;
  963.             end;
  964.             err2 := MNewHandle(btp^.sending_handle, 0);
  965.             if err = noErr then begin
  966.                 err := err2;
  967.             end;
  968.         end;
  969.         TransportHandleSends := err;
  970.     end;
  971.     
  972.     function TransportHandleTransfers(tref:TransportRef): OSStatus;
  973.         var
  974.             err: OSStatus;
  975.     begin
  976.         err := TransportHandleReceives(tref);
  977.         if err = noErr then begin
  978.             err :=TransportHandleSends(tref);
  979.         end;
  980.         TransportHandleTransfers := err;
  981.     end;
  982.     
  983.     function TransportOpenActiveConnection(var tref:TransportRef; dest:Str255; localport:integer; buffer_size:longint): OSStatus;
  984.         var
  985.             btp:TransportRecordPtr;
  986.             err: OSStatus;
  987.             portstr:Str255;
  988.             n:longint;
  989.     begin
  990.         err := TransportCreate(btp, buffer_size);
  991.         if err = noErr then begin
  992.             if have_OT then begin
  993.                 err := BindOTListener(btp^.ep, localport, 0);
  994.                 if err = noErr then begin
  995.                     err:=OTSetAsynchronous(btp^.ep);
  996.                 end;
  997.                 if err = noErr then begin
  998.                     MZero(@btp^.rcvCall, sizeof(btp^.rcvCall));
  999.                     OTInitNetbuf(btp^.rcvCall.addr, @btp^.rcvsin, sizeof(InetAddress));
  1000.         
  1001.                     MZero(@btp^.sndCall, sizeof(btp^.sndCall));
  1002.                     P2C(@dest);
  1003.                     OTInitNetbuf(btp^.sndCall.addr, @btp^.sndsin, OTInitDNSAddress(btp^.sndsin, @dest));
  1004.                     
  1005.                     err := OTConnect(btp^.ep, btp^.sndCall, btp^.rcvCall);
  1006.                     if err = kOTNoDataErr then begin
  1007.                         err := noErr;
  1008.                     end;
  1009.                 end;
  1010.             end else begin
  1011.                 SplitBy (dest, ':', dest, portstr);
  1012.                 StringToNum(portstr, n);
  1013.                 btp^.remote_port := n;
  1014.                 btp^.local_port := localport;
  1015.                 err := TransportNameToAddr(dest, btp^.dnr_token);
  1016.             end;
  1017.             btp^.started_opening := true;
  1018.             if err <> noErr then begin
  1019.                 TransportDestroy(TransportRef(btp));
  1020.             end;
  1021.         end;
  1022.         tref := TransportRef(btp);
  1023.         TransportOpenActiveConnection := err;
  1024.     end;
  1025.  
  1026.     function TransportOpenPassiveConnection(var tref:TransportRef; var localport:integer; buffer_size:longint): OSStatus;
  1027.         var
  1028.             btp:TransportRecordPtr;
  1029.             err:OSStatus;
  1030.     begin
  1031.         err := TransportCreate(btp, buffer_size);
  1032.         if err = noErr then begin
  1033.             if have_OT then begin
  1034.                 btp^.waiting_for_connect := true;
  1035.                 err := BindOTListener(btp^.ep, localport, 1);
  1036.             end else begin
  1037.                 err := MTTCPPassiveOpen(btp^.open_cb, btp^.stream, localport);
  1038.             end;
  1039.             btp^.started_opening := true;
  1040.             if err <> noErr then begin
  1041.                 TransportDestroy(TransportRef(btp));
  1042.             end;
  1043.         end;
  1044.         tref := TransportRef(btp);
  1045.         TransportOpenPassiveConnection := err;
  1046.     end;
  1047.     
  1048.     procedure TransportGetOpenResult(tref:TransportRef; var result: OSStatus);
  1049.         var
  1050.             btp:TransportRecordPtr;
  1051.     begin
  1052.         btp := TransportRecordPtr(tref);
  1053.         Assert(btp <> nil);
  1054.         result := btp^.open_result
  1055.     end;
  1056.     
  1057.     procedure ProcessOpen(btp:TransportRecordPtr);
  1058.         var
  1059.             addr:IPAddr;
  1060.             result: OSStatus;
  1061.     begin
  1062.         Assert(btp <> nil);
  1063.         if btp^.started_opening & (btp^.open_result = inProgress) then begin
  1064.             if have_OT then begin
  1065.                 if btp^.waiting_for_connect then begin
  1066.                     MZero(@btp^.rcvCall, sizeof(btp^.rcvCall));
  1067.                     OTInitNetbuf(btp^.rcvCall.addr, @btp^.rcvsin, sizeof(InetAddress));
  1068.                     result := OTListen(btp^.ep, btp^.rcvCall);
  1069.                     if result = kOTNoDataErr then begin
  1070.                         result := inProgress;
  1071.                     end else begin
  1072.                         btp^.waiting_for_connect := false;
  1073.                         if result = noErr then begin
  1074.                             result := OTAccept(btp^.ep, btp^.ep, btp^.rcvCall);
  1075.                         end;
  1076.                     end;
  1077.                 end else if btp^.disconnect_received then begin
  1078.                     result := -7;
  1079.                 end else if btp^.connect_received then begin
  1080.                     result := btp^.connect_result;
  1081.                 end else if btp^.accept_received then begin
  1082.                     result := btp^.accept_result;
  1083.                 end else if btp^.passcon_received then begin
  1084.                     result := btp^.passcon_result;
  1085.                 end else begin
  1086.                     result := inProgress;
  1087.                 end;
  1088.             end else begin
  1089.                 result := noErr;
  1090.                 if btp^.dnr_token <> nil then begin
  1091.                     TransportGetNameToAddrResult(btp^.dnr_token, result, nil, @addr, 1);
  1092.                     if result = noErr then begin
  1093.                         result := MTTCPActiveOpen(btp^.open_cb, btp^.stream, btp^.local_port, addr, btp^.remote_port);
  1094.                     end;
  1095.                 end;
  1096.                 if result = noErr then begin
  1097.                     result := btp^.open_cb.ioResult;
  1098.                 end;
  1099.             end;
  1100.             btp^.open_result := result;
  1101.         end;
  1102.     end;
  1103.  
  1104.     procedure IdleReceive(btp:TransportRecordPtr);
  1105.         var
  1106.             err: OSStatus;
  1107.             result: OTResult;
  1108.             flags:OTFlags;
  1109.             cb:TCPControlBlock;
  1110.             len, count: longint;
  1111.             space: packed array[1..2048] of byte;
  1112.     begin
  1113.         if btp^.handle_receives then begin
  1114.             len := GetHandleSize(btp^.input_handle);
  1115.             if have_OT then begin
  1116.                 if len < 10240 then begin
  1117.                     result := OTRcv(btp^.ep, @space, SizeOf(space), flags);
  1118.                     if result >= 0 then begin
  1119.                         err := PtrAndHand(@space, btp^.input_handle, result);
  1120.                     end else begin
  1121.                         if (result <> kOTNoDataErr) & (result <> kOTOutStateErr) then begin
  1122.                             err := result;
  1123.                         end else begin
  1124.                             err := noErr;
  1125.                         end;
  1126.                     end;
  1127.                     if err <> noErr then begin
  1128.                         btp^.receive_error := err;
  1129.                     end;
  1130.                 end;
  1131.             end else begin
  1132.                 MTZeroTCPCB(cb, btp^.stream, TCPcsStatus);
  1133.                 err := PBControlSync(@cb);
  1134.                 if err = noErr then begin
  1135.                     count := Min(cb.status.amtUnreadData, 10240 - len);
  1136.                     if count > 0 then begin
  1137.                         err := MSetHandleSize(btp^.input_handle, len + count);
  1138.                         if err = noErr then begin
  1139.                             HLock(btp^.input_handle);
  1140.                             MTZeroTCPCB(cb, btp^.stream, TCPcsRcv);
  1141.                             cb.receive.rcvBuff := btp^.input_handle^;
  1142.                             cb.receive.rcvBuffLength := count;
  1143.                             err := PBControlSync(@cb);
  1144.                             count := cb.receive.rcvBuffLength;
  1145.                             HUnlock(btp^.input_handle);
  1146.                         end;
  1147.                         if err <> noErr then begin
  1148.                             count := 0;
  1149.                             btp^.receive_error := err;
  1150.                         end;
  1151.                         SetHandleSize(btp^.input_handle, len + count);
  1152.                     end;
  1153.                 end;
  1154.             end;
  1155.         end;
  1156.     end;
  1157.     
  1158.     function TransportCharsAvailable(tref:TransportRef): longint;
  1159.         var
  1160.             btp:TransportRecordPtr;
  1161.     begin
  1162.         btp := TransportRecordPtr(tref);
  1163.         Assert(btp <> nil);
  1164.         Assert(btp^.handle_receives);
  1165.         TransportCharsAvailable := GetHandleSize(btp^.input_handle);
  1166.     end;
  1167.     
  1168.     function TransportReceive(tref:TransportRef; buf: Ptr; len:longint; var count:longint): OSStatus;
  1169.         var
  1170.             btp:TransportRecordPtr;
  1171.             err: OSStatus;
  1172.             junk_long: longint;
  1173.     begin
  1174.         btp := TransportRecordPtr(tref);
  1175.         Assert(btp <> nil);
  1176.         Assert(btp^.handle_receives);
  1177.         if btp^.receive_error <> noErr then begin
  1178.             err := btp^.receive_error;
  1179.             btp^.receive_error := noErr;
  1180.             count := 0;
  1181.         end else begin
  1182.             err := noErr;
  1183.             count := Min(len, GetHandleSize(btp^.input_handle));
  1184.             if count > 0 then begin
  1185.                 BlockMoveData(btp^.input_handle^, buf, count);
  1186.                 junk_long := Munger(btp^.input_handle, 0, nil, count, @junk_long, 0);
  1187.             end;
  1188.         end;
  1189.         TransportReceive := err;
  1190.     end;
  1191.     
  1192.     function TransportSend(tref:TransportRef; buf: Ptr; len:longint): OSStatus;
  1193.         var
  1194.             btp:TransportRecordPtr;
  1195.             err: OSStatus;
  1196.     begin
  1197.         btp := TransportRecordPtr(tref);
  1198.         Assert(btp <> nil);
  1199.         Assert(btp^.handle_sends);
  1200.         err := PtrAndHand(buf, btp^.output_handle, len);
  1201.         if err = noErr then begin
  1202.             err := btp^.send_error;
  1203.             btp^.send_error:= noErr;
  1204.         end;
  1205.         TransportSend := err;
  1206.     end;
  1207.     
  1208.     procedure IdleSend(btp: TransportRecordPtr);
  1209.         procedure SwapHandles(var h1, h2:Handle);
  1210.             var
  1211.                 tmph:Handle;
  1212.         begin
  1213.             tmph := h1;
  1214.             h1 := h2;
  1215.             h2 := tmph;
  1216.         end;
  1217.         var
  1218.             err: OSStatus;
  1219.             result: OTResult;
  1220.             len, junk_long:longint;
  1221.     begin
  1222.         if btp^.handle_sends then begin
  1223.             len := GetHandleSize(btp^.output_handle);
  1224.             if btp^.do_send_close & (len = 0) then begin
  1225.                 btp^.handle_sends := false;
  1226.                 TransportSendClose(TransportRef(btp));
  1227.             end else begin
  1228.                 if have_OT then begin
  1229.                     if len > 0 then begin
  1230.                         HLock(btp^.output_handle);
  1231.                         result := OTSnd(btp^.ep, btp^.output_handle^, len, 0);
  1232.                         HUnlock(btp^.output_handle);
  1233.                         if result >= 0 then begin
  1234.                             junk_long := Munger(btp^.output_handle, 0, nil, result, @junk_long, 0);
  1235.                         end else if result <> kOTFlowErr then begin
  1236.                             btp^.send_error := result;
  1237.                             SetHandleSize(btp^.output_handle, 0);
  1238.                         end;
  1239.                     end;
  1240.                 end else begin
  1241.                     if btp^.send_cb.ioResult <> inProgress then begin
  1242.                         HUnlock(btp^.sending_handle);
  1243.                         SetHandleSize(btp^.sending_handle, 0);
  1244.                         if btp^.send_cb.ioResult <> noErr then begin
  1245.                             btp^.send_error := btp^.send_cb.ioResult;
  1246.                             btp^.send_cb.ioResult := noErr;
  1247.                         end;
  1248.                         if len > 0 then begin
  1249.                             SwapHandles(btp^.output_handle, btp^.sending_handle);
  1250.                             HLock(btp^.sending_handle);
  1251.                             btp^.send_wds.buffer := btp^.sending_handle^;
  1252.                             btp^.send_wds.size := len;
  1253.                             btp^.send_wds.term := 0;
  1254.                             MTZeroTCPCB(btp^.send_cb, btp^.stream, TCPcsSend);
  1255.                             btp^.send_cb.send.wds := @btp^.send_wds;
  1256.                             btp^.send_cb.send.pushFlag := 1;
  1257.                             err := PBControlAsync(@btp^.send_cb);
  1258.                         end;
  1259.                     end;
  1260.                 end;
  1261.             end;
  1262.         end;
  1263.     end;
  1264.  
  1265.     procedure TransportSendClose(tref:TransportRef);
  1266.         var
  1267.             btp:TransportRecordPtr;
  1268.             err: OSStatus;
  1269.     begin
  1270.         btp := TransportRecordPtr(tref);
  1271.         Assert(btp <> nil);
  1272.         if btp^.handle_sends then begin
  1273.             btp^.do_send_close := true;
  1274.             IdleSend(btp);
  1275.         end else begin
  1276.             if have_OT then begin
  1277.                 err := OTSndOrderlyDisconnect(btp^.ep);
  1278.             end else begin
  1279.                 err := MTTCPClose(btp^.close_cb, btp^.stream);
  1280.             end;
  1281.         end;
  1282.     end;
  1283.     
  1284.     function TransportGetConnectionState (tref:TransportRef): TCPStateType;
  1285.         var
  1286.             btp:TransportRecordPtr;
  1287.             state:TCPStateType;
  1288.     begin
  1289.         btp := TransportRecordPtr(tref);
  1290.         if btp = nil then begin
  1291.             state := T_Dead;
  1292.         end else if have_OT then begin
  1293.             state := TransportGetConnectionStateOT(btp^.ep);
  1294.         end else begin
  1295.             state := btp^.tstate;
  1296.         end;
  1297.         TransportGetConnectionState := state;
  1298.     end;
  1299.  
  1300.     procedure IdleMacTCPConnectionState(btp:TransportRecordPtr);
  1301.     begin
  1302.         Assert(not have_OT);
  1303.         if btp^.dnr_token <> nil then begin
  1304.             btp^.tstate := T_Opening;
  1305.         end else if btp^.stream = nil then begin
  1306.             btp^.tstate := T_Dead;
  1307.         end else begin
  1308.             btp^.tstate := MTTCPState(btp^.stream);
  1309.         end;
  1310.     end;
  1311.     
  1312.     procedure TransportLowGetStreamPtr(tref:TransportRef; var stream: StreamPtr);
  1313.         var
  1314.             btp:TransportRecordPtr;
  1315.     begin
  1316.         btp := TransportRecordPtr(tref);
  1317.         Assert(btp <> nil);
  1318.         Assert(not have_OT);
  1319.         stream := btp^.stream;
  1320.     end;
  1321.     
  1322.     procedure TransportLowGetEndpointRef(tref:TransportRef; var ep: EndpointRef);
  1323.         var
  1324.             btp:TransportRecordPtr;
  1325.     begin
  1326.         btp := TransportRecordPtr(tref);
  1327.         Assert(btp <> nil);
  1328.         Assert(have_OT);
  1329.         ep := btp^.ep;
  1330.     end;
  1331.  
  1332.     function TransportLowSetOTAckSends(tref:TransportRef; handler: MemoryReleasedProc): OSStatus;
  1333.         var
  1334.             err: OSStatus;
  1335.             btp:TransportRecordPtr;
  1336.     begin
  1337.         btp := TransportRecordPtr(tref);
  1338.         Assert(btp <> nil);
  1339.         Assert(have_OT);
  1340.         err := noErr;
  1341.         if btp^.MemoryReleasedHandler = nil then begin
  1342.             err := OTAckSends(btp^.ep);
  1343.         end;
  1344.         if err = noErr then begin
  1345.             btp^.MemoryReleasedHandler := handler;
  1346.         end;
  1347.         TransportLowSetOTAckSends := err;
  1348.     end;
  1349.  
  1350.     function TransportGetPorts(tref:TransportRef; var localip: IPAddr; var localport: integer; var remoteip: longint; var remoteport: integer): OSStatus;
  1351.         var
  1352.             err: OSStatus;
  1353.             btp: TransportRecordPtr;
  1354.             cb: TCPControlBlock;
  1355.             localBind, remoteBind: TBind;
  1356.             localAddr, remoteAddr: InetAddress;
  1357.     begin
  1358.         btp := TransportRecordPtr(tref);
  1359.         Assert(btp <> nil);
  1360.         localip := 0;
  1361.         localport := 0;
  1362.         remoteip := 0;
  1363.         remoteport := 0;
  1364.         if have_OT then begin
  1365.             btp^.getprotaddr_result := inProgress;
  1366.             OTInitNetbuf(localBind.addr, @localAddr, SizeOf(localAddr));
  1367.             OTInitNetbuf(remoteBind.addr, @remoteAddr, SizeOf(remoteAddr));
  1368.             err := OTGetProtAddress(btp^.ep, localBind, remoteBind);
  1369.             if err = noErr then begin
  1370.                 while btp^.getprotaddr_result = inProgress do begin
  1371.                     OTIdle;
  1372.                 end;
  1373.                 err := btp^.getprotaddr_result;
  1374.             end;
  1375.             if err = noErr then begin
  1376.                 localip := localAddr.fHost;
  1377.                 localport := localAddr.fPort;
  1378.                 remoteip := remoteAddr.fHost;
  1379.                 remoteport := remoteAddr.fPort;
  1380.             end;
  1381.         end else begin
  1382.             MTZeroTCPCB(cb, btp^.stream, TCPcsStatus);
  1383.             err := PBControlSync(@cb);
  1384.             if err = noErr then begin
  1385.                 localip := cb.status.localhost;
  1386.                 localport := cb.status.localport;
  1387.                 remoteip := cb.status.remotehost;
  1388.                 remoteport := cb.status.remoteport;
  1389.             end;
  1390.         end;
  1391.         TransportGetPorts := err;
  1392.     end;
  1393.     
  1394.     const
  1395.         max_tcp_listeners = 20;
  1396.     
  1397.     type
  1398.         TransportListenRecord = record
  1399.             case boolean of
  1400.             false:(
  1401.                 mt_buffer_size:longint;
  1402.                 mt_listeners_count:integer;
  1403.                 mt_listeners:array[1..max_tcp_listeners] of TransportRef;
  1404.                 localport:integer;
  1405.             )
  1406.             true:(
  1407.                 ep: EndpointRef;
  1408.             )
  1409.         end;
  1410.         TransportListenRecordPtr = ^TransportListenRecord;
  1411.  
  1412.     function TransportListen(var token:Ptr; localport:integer; listeners:integer; buffer_size:longint):OSStatus;
  1413.         var
  1414.             lp:TransportListenRecordPtr;
  1415.             err, junk:OSStatus;
  1416.             i:integer;
  1417.     begin
  1418.         lp := nil;
  1419.         err := OpenTransportSystem;
  1420.         if err = noErr then begin
  1421.             err := MNewPtr(lp, SizeOf(TransportListenRecord));
  1422.             if err = noErr then begin
  1423.                 if have_OT then begin
  1424.                     err := CreateOTEndpoint(lp^.ep, nil, lp);
  1425.                     if err = noErr then begin
  1426.                         err := BindOTListener(lp^.ep, localport, 99);
  1427.                         if err <> noErr then begin
  1428.                             junk := OTCloseProvider(lp^.ep);
  1429.                         end;
  1430.                     end;
  1431.                 end else begin
  1432.                     lp^.localport := localport;
  1433.                     lp^.mt_listeners_count := listeners;
  1434.                     lp^.mt_buffer_size := buffer_size;
  1435.                     for i := 1 to lp^.mt_listeners_count do begin
  1436.                         lp^.mt_listeners[i] := nil;
  1437.                     end;
  1438.                 end;
  1439.             end;
  1440.         end;
  1441.         if err <> noErr then begin
  1442.             MDisposePtr(lp);
  1443.         end;
  1444.         token := Ptr(lp);
  1445.         TransportListen := err;
  1446.     end;
  1447.  
  1448.     function TransportGetListenerConnection(token:Ptr; var tref:TransportRef):OSStatus;
  1449.         var
  1450.             err, result:OSStatus;
  1451.             lp:TransportListenRecordPtr;
  1452.             i:integer;
  1453.             rcvCall:TCall;
  1454.             rcvsin:InetAddress;
  1455.             btp:TransportRecordPtr;
  1456.     begin
  1457.         lp := TransportListenRecordPtr(token);
  1458.         if lp = nil then begin
  1459.             err := -28;
  1460.             tref := nil;
  1461.         end else begin
  1462.             err := inProgress;
  1463.             if have_OT then begin
  1464.                 MZero(@rcvCall, sizeof(rcvCall));
  1465.                 OTInitNetbuf(rcvCall.addr, @rcvsin, sizeof(InetAddress));
  1466.                 result := OTListen(lp^.ep, rcvCall);
  1467.                 if result = kOTNoDataErr then begin
  1468.                     err := inProgress;
  1469.                 end else if result <> noErr then begin
  1470.                     err := result;
  1471.                 end else begin
  1472.                     err := TransportCreate(btp, 0);
  1473.                     if err = noErr then begin
  1474.                         tref := TransportRef(btp);
  1475.                         btp^.started_opening := true;
  1476.                         err := OTAccept(lp^.ep, btp^.ep, rcvCall);
  1477.                         if err = noErr then begin
  1478.                             err:=OTSetAsynchronous(btp^.ep);
  1479.                         end;
  1480.                         if err <> noErr then begin
  1481.                             TransportDestroy(tref);
  1482.                         end;
  1483.                     end;
  1484.                 end;
  1485.             end else begin
  1486.                 for i := 1 to lp^.mt_listeners_count do begin
  1487.                     if (lp^.mt_listeners[i] = nil) then begin
  1488.                         err := TransportOpenPassiveConnection(lp^.mt_listeners[i], lp^.localport, lp^.mt_buffer_size);
  1489.                         leave; { only create one listener, that allows the listeners to be shared a bit better }
  1490.                     end;
  1491.                 end;
  1492.  
  1493.                 err := inProgress;
  1494.                 for i := 1 to lp^.mt_listeners_count do begin
  1495.                     if (lp^.mt_listeners[i] <> nil) then begin
  1496.                         TransportGetOpenResult(lp^.mt_listeners[i], result);
  1497.                         case result of
  1498.                             inProgress: begin
  1499.                             end;
  1500.                             noErr:begin
  1501.                                 tref := lp^.mt_listeners[i];
  1502.                                 lp^.mt_listeners[i] := nil;
  1503.                                 err := noErr;
  1504.                                 leave;
  1505.                             end;
  1506.                             otherwise begin
  1507.                                 DebugStr(concat('Immediate destroy? ',NumToStr(result)));
  1508.                                 TransportDestroy(lp^.mt_listeners[i]);
  1509.                             end;
  1510.                         end;
  1511.                     end;
  1512.                 end;
  1513.             end;
  1514.         end;
  1515.         TransportGetListenerConnection := err;
  1516.     end;
  1517.     
  1518.     procedure TransportDestroyListener(var token:Ptr);
  1519.         var
  1520.             junk:OSStatus;
  1521.             lp:TransportListenRecordPtr;
  1522.             i:integer;
  1523.     begin
  1524.         lp := TransportListenRecordPtr(token);
  1525.         if lp <> nil then begin
  1526.             if have_OT then begin
  1527.                 junk := OTCloseProvider(lp^.ep);
  1528.             end else begin
  1529.                 for i := 1 to lp^.mt_listeners_count do begin
  1530.                     TransportDestroy(lp^.mt_listeners[i]);
  1531.                 end;
  1532.                 lp^.mt_listeners_count := 0;
  1533.             end;
  1534.             MDisposePtr(token);
  1535.         end;
  1536.     end;
  1537.  
  1538.     function CreateOTUDPEndpoint(var ep:EndpointRef; proc:OTNotifyProcPtr; var localport: integer; context:univ Ptr):OSErr;
  1539.         var
  1540.             err, junk: OSStatus;
  1541.             config: Str255;
  1542.             info: TEndpointInfo;
  1543.             reqsin, retsin:InetAddress;
  1544.             req, ret:TBind;
  1545.     begin
  1546.         config := 'udp';
  1547.         P2C(@config);
  1548.         ep:=OTOpenEndpoint(OTCreateConfiguration(@config),0,info,err);
  1549.         if (err = noErr) & (proc <> nil) then begin
  1550.             err:=OTInstallNotifier(ep, proc, context);
  1551.         end;
  1552.  
  1553.         if err = noErr then begin
  1554.             if localport <> 0 then begin
  1555.                 OTInitInetAddress(reqsin, localport, 0);
  1556.                 OTInitNetbuf(req.addr, @reqsin, sizeof(InetAddress));
  1557.             end else begin
  1558.                 OTInitNetbuf(req.addr, nil, 0);
  1559.             end;
  1560.             req.qlen := 1;
  1561.             
  1562.             MZero(@ret, sizeof(ret));
  1563.             OTInitNetbuf(ret.addr, @retsin, sizeof(InetAddress));
  1564.             err := OTBind(ep, @req, @ret);
  1565.             localport := retsin.fPort;
  1566.         end;
  1567.         if (err = noErr) & (localport <> 0) & (localport <> retsin.fPort) then begin
  1568.             err := couldNotGetRequestedPortErr;
  1569.         end;
  1570.         if err = noErr then begin
  1571.             err:=OTSetNonBlocking(ep);
  1572.         end;
  1573.         if err <> noErr then begin
  1574.             junk := OTCloseProvider(ep);
  1575.         end;
  1576.         CreateOTUDPEndpoint := err;
  1577.     end;
  1578.     
  1579.     procedure UDPEventHandlerOT (tup: TransportUDPRecordPtr; event: OTEventCode; result: OTResult; cookie: univ Ptr);
  1580.     begin
  1581.         cookie := cookie; { UNUSED! }
  1582.         result := result; { Unused! }
  1583.         case event of
  1584.             T_DATA: begin
  1585.                 Inc(tup^.received_packets);
  1586.             end;
  1587.             otherwise
  1588.                 ;
  1589.         end;
  1590.     end;
  1591.  
  1592.     function TransportUDPOpenPort(var tref: TransportUDPRef; var localport: integer; buffer_size:longint): OSStatus;
  1593.         var
  1594.             err:OSStatus;
  1595.             tup: TransportUDPRecordPtr;
  1596.     begin
  1597.         buffer_size := Pin(10240, buffer_size, 64512);
  1598.         tup := nil;
  1599.         err := OpenTransportSystem;
  1600.         if err = noErr then begin
  1601.             err := MNewPtr(tup, SizeOf(TransportUDPRecord));
  1602.             if err = noErr then begin
  1603.                 if have_OT then begin
  1604.                     tup^.received_packets := 0;
  1605.                     tup^.read_packets := 0;
  1606.                     err := CreateOTUDPEndpoint(tup^.ep, @UDPEventHandlerOT, localport, tup);
  1607.                 end else begin
  1608.                     tup^.stream := nil;
  1609.                     err := MNewPtr(tup^.stream_buffer, buffer_size);
  1610.                     if err = noErr then begin
  1611.                         err := MTUDPCreate(tup^.stream, localport, @tup^.outstanding_packets, tup^.stream_buffer, buffer_size);
  1612.                     end;
  1613.                 end;
  1614.                 if err <> noErr then begin
  1615.                     TransportUDPDestroy(TransportUDPRef(tup));
  1616.                 end;
  1617.             end;
  1618.         end;
  1619.         tref := TransportUDPRef(tup);
  1620.         TransportUDPOpenPort := err;
  1621.     end;
  1622.     
  1623.     procedure TransportUDPDestroy (var tref: TransportUDPRef);
  1624.         var
  1625.             err, junk: OSStatus;
  1626.             tup: TransportUDPRecordPtr;
  1627.     begin
  1628.         err := noErr;
  1629.         tup := TransportUDPRecordPtr(tref);
  1630.         if tup <> nil then begin
  1631.             if have_OT then begin
  1632.                 if tup^.ep <> nil then begin
  1633.                     junk := OTCloseProvider(tup^.ep);
  1634.                 end;
  1635.             end else begin
  1636.                 if tup^.stream <> nil then begin
  1637.                     err := MTUDPRelease(tup^.stream);
  1638.                 end;
  1639.                 MDisposePtr(tup^.stream_buffer);
  1640.             end;
  1641.             MDisposePtr(tup);
  1642.             tref := nil;
  1643.         end;
  1644.     end;
  1645.     
  1646.     const
  1647.         max_udp_datalen = 2048;
  1648.         
  1649.     function TransportUDPDatagramsAvailable (tref: TransportUDPRef): longint;
  1650.         var
  1651.             tup: TransportUDPRecordPtr;
  1652.     begin
  1653.         tup := TransportUDPRecordPtr(tref);
  1654.         Assert(tup <> nil);
  1655.         if have_OT then begin
  1656.             TransportUDPDatagramsAvailable := tup^.received_packets - tup^.read_packets;
  1657.         end else begin
  1658.             TransportUDPDatagramsAvailable := tup^.outstanding_packets;
  1659.         end;
  1660.     end;
  1661.  
  1662.     function TransportUDPRead (tref: TransportUDPRef; var remoteIP: longint; var remoteport: integer;
  1663.                                     var datap: ptr; var datalen: integer): OSStatus;
  1664.         var
  1665.             err:OSStatus;
  1666.             tup: TransportUDPRecordPtr;
  1667.             udata:TUnitData;
  1668.             flags: OTFlags;
  1669.             srcsin: InetAddress;
  1670.             tmp_packets: longint;
  1671.     begin
  1672.         tup := TransportUDPRecordPtr(tref);
  1673.         Assert(tup <> nil);
  1674.         if have_OT then begin
  1675.             err := MNewPtr(datap, max_udp_datalen);
  1676.             if err = noErr then begin
  1677.                 MZero(@udata, SizeOf(udata));
  1678.                 OTInitNetbuf(udata.addr, @srcsin, SizeOf(srcsin));
  1679.                 OTInitNetbuf(udata.udata, datap, max_udp_datalen);
  1680.                 tmp_packets := tup^.received_packets;
  1681.                 err := OTRcvUData(tup^.ep,udata, flags);
  1682.                 if err = noErr then begin
  1683.                     Inc(tup^.read_packets);
  1684.                     datalen := udata.udata.len;
  1685.                     remoteIP := srcsin.fHost;
  1686.                     remoteport := srcsin.fPort;
  1687.                 end;
  1688.                 if (err = kOTNoDataErr) then begin
  1689.                     tup^.read_packets := tmp_packets;
  1690.                 end;
  1691.             end;
  1692.             if err <> noErr then begin
  1693.                 MDisposePtr(datap);
  1694.             end;
  1695.         end else begin
  1696.             err := MTUDPRead(tup^.stream, @tup^.outstanding_packets, remoteIP, remoteport, datap, datalen);
  1697.         end;
  1698.         TransportUDPRead := err;
  1699.     end;
  1700.  
  1701.     function TransportUDPReturnBuffer (tref: TransportUDPRef; datap: ptr): OSStatus;
  1702.         var
  1703.             err:OSStatus;
  1704.             tup: TransportUDPRecordPtr;
  1705.     begin
  1706.         err := noErr;
  1707.         tup := TransportUDPRecordPtr(tref);
  1708.         Assert(tup <> nil);
  1709.         if tup <> nil then begin
  1710.             if have_OT then begin
  1711.                 MDisposePtr(datap);
  1712.             end else begin
  1713.                 err := MTUDPReturnBuffer(tup^.stream, datap);
  1714.             end;
  1715.         end;
  1716.         TransportUDPReturnBuffer := err;
  1717.     end;
  1718.  
  1719.     function TransportUDPWrite (tref: TransportUDPRef; remoteIP: longint; remoteport: integer;
  1720.                                     datap: ptr; datalen: integer; checksum: boolean): OSStatus;
  1721.         var
  1722.             err:OSStatus;
  1723.             tup: TransportUDPRecordPtr;
  1724.             udata:TUnitData;
  1725.             destsin: InetAddress;
  1726.     begin
  1727.         err := noErr;
  1728.         tup := TransportUDPRecordPtr(tref);
  1729.         Assert(tup <> nil);
  1730.         if tup <> nil then begin
  1731.             if have_OT then begin
  1732.                 MZero(@udata, SizeOf(udata));
  1733.                 OTInitInetAddress(destsin, remoteport, remoteIP);
  1734.                 OTInitNetbuf(udata.addr, @destsin, SizeOf(destsin));
  1735.                 OTInitNetbuf(udata.udata, datap, datalen);
  1736.                 err := OTSndUData(tup^.ep,udata);
  1737.             end else begin
  1738.                 err := MTUDPWrite(tup^.stream, remoteIP, remoteport, datap, datalen, checksum);
  1739.             end;
  1740.         end;
  1741.         TransportUDPWrite := err;
  1742.     end;
  1743.  
  1744.     procedure IdleTransports;
  1745.         var
  1746.             this, next:TransportRecordPtr;
  1747.     begin
  1748.         this := TransportRecordPtr(transports.qHead);
  1749.         while this <> nil do begin
  1750.             next := this^.next;
  1751.             ProcessOpen(this);
  1752.             if this^.open_result = noErr then begin
  1753.                 IdleSend(this);
  1754.                 IdleReceive(this);
  1755.             end;
  1756.             if not have_OT then begin
  1757.                 IdleMacTCPConnectionState(this);
  1758.             end;
  1759.             this := next;
  1760.         end;
  1761.     end;
  1762.         
  1763.     procedure IdleTransport;
  1764.     begin
  1765.         IdleDNRs;
  1766.         IdleTransports;
  1767.     end;
  1768.     
  1769.     function HasOTLib:boolean;
  1770.     begin
  1771. {$IFC GENERATINGPOWERPC}
  1772.         HasOTLib := longint(@InitOpenTransport) <> kUnresolvedCFragSymbolAddress;
  1773. {$ELSEC}
  1774.         HasOTLib := true;
  1775. {$ENDC}
  1776.     end;
  1777.  
  1778.     procedure ConfigureTransport(allow_OT: Boolean);
  1779.         var
  1780.             gv:longint;
  1781.     begin
  1782.         if not allow_OT then begin
  1783.             have_OT := false;
  1784.         end else begin
  1785.             have_OT := (Gestalt(gestaltOpenTpt, gv) = noErr) & (BAND(gv, gestaltOpenTptPresent) <> 0) & (BAND(gv, gestaltOpenTptTCPPresent) <> 0) & HasOTLib;
  1786.         end;
  1787.     end;
  1788.     
  1789.     function InitTransport(var msg: integer):OSStatus;
  1790.     begin
  1791.         msg := msg; { Unused }
  1792.         hack_MemoryReleasedProc := nil;
  1793.         gMyDeferredTaskHandlerProc := NewProc(@MyDeferredTaskHandler, uppDeferredTaskProcInfo);
  1794.         tcp_is_open := false;
  1795.         dnrs.qHead := nil;
  1796.         dnrs.qTail := nil;
  1797.         transports.qHead := nil;
  1798.         transports.qTail := nil;
  1799.         is_ref := nil;
  1800.         InitTransport := noErr;
  1801.     end;
  1802.     
  1803.     procedure FinishTransport;
  1804.     begin
  1805.         WaitForDNRCompletions;
  1806.         CloseTransportSystem;
  1807.     end;
  1808.     
  1809.     procedure StartupTransport;
  1810.     begin
  1811.         StartupPreserveA5;
  1812.         StartupTCPUtils;
  1813.         SetStartup(InitTransport, IdleTransport, 0, FinishTransport);
  1814.     end;
  1815.     
  1816. end.
  1817.  
  1818.